import { Inject, Logger, Provide } from '@midwayjs/decorator';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { NovelEntity } from 'src/entity/novel/novel';
import { Repository  } from "typeorm";
import { Context } from '@midwayjs/koa';

import  {Utils} from '../utils'
import { HttpService } from '@midwayjs/axios';
// import { novelnumDTO } from 'src/dto/novel';
import   userconfig   from '../private/clienconfig'
import { payOtions } from 'src/interface';
import * as md5 from 'md5'
import { JwtService } from '@midwayjs/jwt';
import { OrderpayDTO } from 'src/dto/order';
import { AddressEntity } from 'src/entity/userinfo/payAddress';
import { OrderEntity } from 'src/entity/order/orderentity';
import { ILogger } from '@midwayjs/logger';
import { SystemEntity } from 'src/entity/admin/system';
import { RedisService } from '@midwayjs/redis';
// import  axios  from 'axios'

@Provide()
export class PayService {

    @Inject()
    ctx: Context

    @Inject()
    jwtService: JwtService;

    @Inject()
    httpService: HttpService;

    @Logger('coreLogger')
    logger: ILogger;
    
    @Inject('utils')
    utils: Utils;
    @InjectEntityModel(NovelEntity)
    NovelModel: Repository<NovelEntity>;
    @InjectEntityModel(SystemEntity)
    SystemModel: Repository<SystemEntity>;
    @InjectEntityModel(OrderEntity)
    OrderModel: Repository<OrderEntity>;
    @InjectEntityModel(AddressEntity)
    AddressModel: Repository<AddressEntity>;
 
    @Inject()
    redisService: RedisService;


  // 用户付款   小说id  


  /*  
     付款接口流程: 
      重点:  知道内部的流程怎么写
       1.  传参   a.书的id  b.(账单地址 , 信用卡)  ,  extreaid( 账单地址 , 信用卡 但是是存在数据库中 表示之前已经写个一次了) 
       2.  用户名需要传递?  不需要    后端直接通过 token 来解析获取的  
       3.  判断 extreaid  有没有 ,有就 查询 extreaid  获取( 账单地址 , 信用卡) 同时 加一个where(  用户名  + extreaid )
       4.  没有的话,  通过对方传递 (账单地址 , 信用卡)   进行 存入数据库中  
       5.  创建订单号 

       6.  将查询的书   获取价格  where (  onSale :  true 是否在售卖)   , 能查到 说明满足条件
       7.  插入一个订单 数据库    (  订单号 , 价格 ,  用户id  , 书id , 书名 ,  支付状态 :  0  : 未支付     )
                                  订单信息:  最好写死了, 不用去联立任何数据库    , 假设一年前  id=15  name "斗破"  一年后 id=15  name ="雷雨"
       8.  发送请求, 让第三方 去扣款 或者得到url连接 让对方跳转去付款

  */

       /* 
      //   注意 不能使用 中间件拦截,  控制器不能一样,  为什么?  因为控制器 会自动拦截没有token的人 
        支付回调:  第三方  发生请求,告诉我们 对方支付了 , 让我们 把 支付状态 :  0  => 1  变成已经支付 
        // 这个第三方是谁 还不能指定  ( 指定 ip地址  (跨域 是可以指定某某ip进来 ))
                   1. 接受到参数后, 将参数 除了 sign 签名 不进行 签名加密以外, 我们要对其他的参数进行签名校验 
                      我们自己做的签名校验( 拿对方传递过来参数来做)   
                       ( 除了 sign 不校验  ) 加密后 =  sign2 
                       if( sign == sing2){
                          说明是对方
                           修改数据库状态(    where : {   OrderSn :machOrderNo}     ).update( status : 1)



                       }

       
       
       */




  async  userpay(novelid:OrderpayDTO) {
      //  谁买?  解析用户
      console.log('n3333333333333333ovelid' ,novelid);
      
       let    user   =  await this.getuserinfo()

      //   查数据库 看书的价格 
      var  book    = await  this.NovelModel.find( {  where : {  id : novelid.id } })
       let    price = book[0].Price*100
      //  let    price = 1*100
       var  extrea
      // console.log( "价格", price);
      // console.log("novelid",novelid.extra);
      
    //  如果有id 就查询id 的 
      if( novelid.extraID ){
          
        console.log("id来了",novelid.extraID ,user.id  );
        // 如果带以前的支付的记录 查询获取内容
        console.log("123132");
        
         extrea =  await this.AddressModel.createQueryBuilder("address")
        .leftJoinAndSelect("address.userid", "user")
        .where("address.id = :id", { id: novelid.extraID })
        .andWhere("user.id = :userid", { userid: user.id })
        .getOne()


          console.log('数据库',extrea);

          // 待测试 通过
          console.log(extrea);
          
          if(!extrea){
              return { 
                  code:20000,
                  message:'extraID fail'
              }
          }


      }else{ 
    

           extrea = { 
          userid:user.id,
          email:    novelid.extra.email,
          shippingFirstName: novelid.extra.billingFirstName,
          shippingLastName:novelid.extra.billingLastName,
          shippingAddress:novelid.extra.billingAddress,
          shippingCity:novelid.extra.billingCity,
          shippingState:novelid.extra.billingState,
          shippingZipCode:novelid.extra.billingZipCode,
          shippingCountry:novelid.extra.billingCountry,
          shippingPhone:novelid.extra.billingPhone,
          billingFirstName:novelid.extra.billingFirstName,
          billingLastName:novelid.extra.billingLastName,
          billingAddress:novelid.extra.billingAddress,
          billingCity:novelid.extra.billingCity,
          billingState:novelid.extra.billingState,
          billingCountry:novelid.extra.billingCountry,
          billingZipCode:novelid.extra.billingZipCode,
          billingPhone:novelid.extra.billingPhone,
          cardNo:novelid.extra.cardNo,
          expYear:novelid.extra.expYear,
          cvv:novelid.extra.cvv,
          expMonth:novelid.extra.expMonth

         }

        //  存入数据库    
        console.log("藏入数据库");
            
        var newextrea  = await this.AddressModel.save(extrea)
         
         console.log( '存入数据库',newextrea);
         
        // console.log("存入账单地址", result2);
        

      }
        




      
      extrea = JSON.stringify(extrea)
      console.log('extrea234',extrea);
      //   创建订单
      let OrderSN = this.createOrderSn(user.id)


      // // 插入订单       
      console.log("订单入库");
      var orderdata:any=  { 
        userId: user.id, 
        payaddress:novelid.extraID || newextrea.id,  
        orderSn :OrderSN  ,
        orderPrice:book[0].Price,
        actualPrice:book[0].Price,
        pay_type:0,
        status:0,
        novel:book[0]
        
      
      }
      if(novelid.agent){
        //  查询系统折扣 
        // this.SystemModel.findOne({  where:{ id:1 } })
        let num = await this.getdiscount()
        orderdata.shareUserId  = novelid.agent
        orderdata.discount_amount  = num
        orderdata.brokeragePrice = (orderdata.actualPrice *  Number(num))/100 
      }

      console.log(' orderdata.brokeragePrice ' ,  orderdata.brokeragePrice );
      

      
    await this.OrderModel.save(orderdata)
      // console.log(  "插入订单" ,asb);
      








      var data = { 
        OrderSN,
        returnUrl:  novelid.returnUrl,
        money:price, // 查价格
        subject:book[0].name , // 查书名1
        body:"bookOfTheMall", // 商品描述
        extra:extrea
      }
      // console.log(data);
      
 
      // 发送请求给第三方服务商
      let result3  =  await this.commitOrder(data)
      // let result3 ={ 
      //   errCode:"001"
      // }
      console.log( "支付结果",result3);
      
      if(result3.errCode =="0014"){
          return   { 
            code:20000,
            message:"PAY FAIL"  
          }
      }
      if(result3.retCode =="FAIL"){
         return {  
          code:40004,
          message:result3.retMsg
         } 
      }

     
      return  { 
            code:20000,
            data: {
              ...result3.payParams
                // payUrl:'https://pay.storepay.cn/api/cashier/pc/platform_pay?payParams=eyJleHRlbmRQYXJhbXMiOnsiY3JlcSI6ImV5SjBhSEpsWlVSVFRXVjBhRzlrVG05MGFXWnBZMkYwYVc5dVZWSk1Jam9pYUhSMGNITTZMeTl2WTNBdWFXeHJjbWgxWWk1amIyMHZZWEJwTDNSb2NtVmxSRk5OWlhSb2IyUk9iM1JwVW1WamRpNWtieUlzSW5Sb2NtVmxSRk5UWlhKMlpYSlVjbUZ1YzBsRUlqb2lOalJtT0RjNU9UVXROVE5tTlMwME1XTmpMVGc1WVdNdFlUSTBabVk1WkRnNU5XSmlJbjAiLCJ0ZXJtVXJsIjoiIiwidGhyZWVEU1Nlc3Npb25EYXRhIjoiZXlKMGFISmxaVVJUVFdWMGFHOWtUbTkwYVdacFkyRjBhVzl1VlZKTUlqb2lhSFIwY0hNNkx5OXZZM0F1YVd4cmNtaDFZaTVqYjIwdllYQnBMM1JvY21WbFJGTk5aWFJvYjJST2IzUnBVbVZqZGk1a2J5SXNJblJvY21WbFJGTlRaWEoyWlhKVWNtRnVjMGxFSWpvaU5qUm1PRGM1T1RVdE5UTm1OUzAwTVdOakxUZzVZV010WVRJMFptWTVaRGc1TldKaUluMCIsIm1kIjoiNjRmODc5OTUtNTNmNS00MWNjLTg5YWMtYTI0ZmY5ZDg5NWJiIiwicGFSZXEiOiJQWTE2MzI5MjAyMjExMDgxMTM0MDY0ODQ2ODU3In0sInBheU9yZGVySWQiOiJQMDEyMDIyMTEwODEwMzQwMzAwMDEwNTEiLCJtY2hJZCI6MjAwMDAxNjMsImFjdGlvbiI6Imh0dHBzOi8vb2NwLmlsa3JodWIuY29tL2FwaS90aHJlZURTTWV0aG9kLmRvIn0='
            },
            message:result3.retMsg

      }  
 
  }




  async notify(body:any){
      let { sign  , ...check  } = body
      this.logger.info('通知参数',body );
        
    //  签名校验
    let sign2 =  await  this.createSign(check)
      console.log(sign2 ==sign );
      
         if( true){
           check.mchOrderNo  // 支付订单
           check.amount  //支付金额
          //   修改订单支付状态
          //  修改订单状态
          console.log( 'check.amount付款金额: ',  check.amount);
          
           let Order  =await this.OrderModel.findOne( {    relations: ["novel"] , where :  { orderSn :  check.mchOrderNo  ,actualPrice: check.amount }   })
           Order.orderStatus = 1
           Order.pay_type = 1
           Order.status = 3
           Order.novel.sales =   Order.novel.sales +1
           Promise.all(  [this.NovelModel.save( Order.novel)  , this.NovelModel.save( Order.novel)] )
          //   更改状态 更改销量
      

        // let Order =   await this.OrderModel.createQueryBuilder().update()
        //   .set(  { orderStatus:1  , pay_type :1  , status:3 })
        //   .where( { orderSn :  check.mchOrderNo  ,actualPrice: check.amount })
        //   .execute();

 
               console.log(Order);




         }


         return {
          code:20000,
          msg:"SUCCESS",
          message:"SUCCESS",
          data:{ 
            SUCCESS:"SUCCESS"
          },
          return_code: 'SUCCESS',
          return_msg: 'OK'
        }
  }

 




















  // 创建订单
 //  用户id 支付产品ID  商户订单号  币currency  amount  returnUrl
  //商品描述 body  小说名  
//  客户ip  clientIp
// amount           小说价格
// subject    String(64)	测试商品名称 小说名  
// extra    送货地址json
// sign 签名

// 考虑需要接受的参数
// 提交订单

//  专门 发送请求   只需要填写一些代填的数据即可 
   async commitOrder(content:payOtions){
    // 专门发送请求给第三方 获取  支付参数 : 跳转的url
    console.log("ipipipip",await this.utils.getReqIP(this.ctx) );
    console.log("ipipipip",typeof await this.utils.getReqIP(this.ctx) );
    
    var paydata = { 
        productId:8001,
        mchId:userconfig.mchId ,    //商户id
        appId:userconfig.appId,   // 应用ID 
        mchOrderNo: content.OrderSN,
        currency:"USD" ,// 币种 美元
        amount:content.money , // 查询数据库 最终的金额,
        clientIp: '4.43.69.64',// 用户ip 
        // clientIp: (await this.utils.getReqIP(this.ctx)),// 用户ip 
        returnUrl:content.returnUrl, // 前端跳转连接
        notifyUrl:userconfig.notifyUrl,   // "支付通知"
        subject:content.subject , //  商品标题
        body:content.body,    // 商品描述
        extra:content.extra,  // 邮箱、送货地址、账单地址 
     

    }

    //                后端发送请求, 没有使用axios 而是用了自带的请求器 midway 自带的

  
    // var url = 'https://pay.storepay.cn/api/pay/create_order'
    var url = 'https://pay.storepay.cn/api/pay/create_order'
     const {data} = await this.httpService.request({
      method: 'POST',
      headers: { 'content-type': 'application/x-www-form-urlencoded' },
      data: { 
        ...paydata,
        sign:await this.createSign(paydata) // 签名算法
      },
      url,
     })

      console.log( {...paydata} );
      console.log( await this.createSign(paydata));
      
      


     console.log(data);
    return data
    



   }

   
//  创建订单 创建一个唯一的订单号  时间戳+用户id   同个人不可能同时下2个订单 也不会同时进入一个请求 
   createOrderSn(id:number) {
    var timer = new Date()
      return  timer.getFullYear() +""+ ((timer.getMonth()+1).toString().padStart(2,"0"))+timer.getDate()+timer.getMilliseconds().toString().padStart(3,"0")+((timer.getHours()+6).toString().padStart(2,"0"))+timer.getSeconds().toString().padStart(2,"0")+timer.getMinutes()+(id+1234)
 
}



  // 获得用户信息   解析token 得知 对方 用户id
  async getuserinfo():Promise<any>{
      // console.log("token",this.ctx.get("authorization"));
      
    let result     =await  this.jwtService.verify(this.ctx.get("authorization").replace("Bearer ",""),userconfig.secret , { complete: true,})

    // console.log("解析", typeof result == 'object');
    if( typeof result == 'object'){
      console.log(result);
      
      return result.payload
    }
    return  { }
  }

//   创建签名 
 async  createSign(obj) {
    //签名算法（把所有的非空的参数，按字典顺序ASCILL组合起来+key,然后md5加密，再把加密结果都转成大写的即可）
      //  将对象转化为数组进行排序
      //  将需要加入签名的 参数 放在一个对象 keys转化为一个数组   sort() 默认就是ASCILL 排列方式
      let  arr  =  Object.keys(obj).sort()

      var stra =arr.reduce( (v,e)=>{ 
        v =  v + e+'='+obj[e]+"&"
       return  v
    },"" )
    //  排序完成后 ,  再额外加 可以
    console.log("签名" , stra );
    

      let stringSignTemp = stra + 'key=' + userconfig.pay_api_key;
      //  MD5 加密再转大写
      console.log("签名2",stringSignTemp);
      stringSignTemp = md5(stringSignTemp);

      var  aa =   md5('42')
      aa.toUpperCase()
      // console.log('aa',aa);
      
      
      let signValue = stringSignTemp.toUpperCase();
      console.log("签名3",signValue);

    return signValue
}

  async  getdiscount(){

      //  先查询  redis 有没有
      let num     =  await this.redisService.get('discount')
      console.log("redis" ,num);
      
      if(num  == null){
         let num2   = await this.SystemModel.findOne({ where : { id:1 }})
        this.redisService.set('discount',num2.discount)
     
          
          return  num2.discount
      }
      return  num
   
  }

}
